#include "wx/wxprec.h"
#include "wx/collpane.h"
#include "wx/toplevel.h"
#include "wx/sizer.h"
#include "wx/panel.h"
#include "wx/gtk/private.h"
#include "wx/gtk/win_gtk.h"
#include <gtk/gtkexpander.h>

extern "C" {
  static void gtk_collapsiblepane_expanded_callback( GObject    *object,
      GParamSpec *param_spec,
      wxCollapsiblePane *p ) {
    wxSize sz;
    if( p->IsExpanded() ) {
      sz = p->m_szCollapsed;
      wxSize panesz = p->GetPane()->GetBestSize();
      sz.x = wxMax( sz.x, panesz.x );
      sz.y += gtk_expander_get_spacing( GTK_EXPANDER( p->m_widget ) ) + panesz.y;
    } else {
      sz = p->m_szCollapsed;
    }
    p->SetMinSize( sz );
    if( p->HasFlag( wxCP_NO_TLW_RESIZE ) ) {
      wxCollapsiblePaneEvent ev( p, p->GetId(), p->IsCollapsed() );
      p->GetEventHandler()->ProcessEvent( ev );
      return;
    }
    wxTopLevelWindow *
    top = wxDynamicCast( wxGetTopLevelParent( p ), wxTopLevelWindow );
    if( top && top->GetSizer() ) {
      wxSize sz = top->GetSizer()->CalcMin();
      if( top->m_mainWidget ) {
        gtk_window_set_resizable( GTK_WINDOW( top->m_widget ), p->IsExpanded() );
        GdkGeometry geom;
        geom.min_width = sz.x;
        geom.min_height = sz.y;
        gtk_window_set_geometry_hints( GTK_WINDOW( top->m_widget ), ( GtkWidget* ) NULL, &geom, GDK_HINT_MIN_SIZE );
        top->m_width = sz.x;
        top->m_height = sz.y;
        int client_x = top->m_miniEdge;
        int client_y = top->m_miniEdge + top->m_miniTitle;
        int client_w = top->m_width - 2 * top->m_miniEdge;
        int client_h = top->m_height - 2 * top->m_miniEdge - top->m_miniTitle;
        if( client_w < 0 ) {
          client_w = 0;
        }
        if( client_h < 0 ) {
          client_h = 0;
        }
        gtk_pizza_set_size( GTK_PIZZA( top->m_mainWidget ),top->m_wxwindow,client_x, client_y, client_w, client_h );
        gtk_widget_set_size_request( top->m_wxwindow, sz.x, sz.y );
      }
    }
    if( p->m_bIgnoreNextChange ) {
      p->m_bIgnoreNextChange = false;
      return;
    }
    wxCollapsiblePaneEvent ev( p, p->GetId(), p->IsCollapsed() );
    p->GetEventHandler()->ProcessEvent( ev );
  }
}

static void gtk_collapsiblepane_insert_callback( wxWindow* parent, wxWindow* child ) {
  gtk_container_add( GTK_CONTAINER( parent->m_widget ), child->m_widget );
}

IMPLEMENT_DYNAMIC_CLASS( wxCollapsiblePane, wxGenericCollapsiblePane )
BEGIN_EVENT_TABLE( wxCollapsiblePane, wxGenericCollapsiblePane )
  EVT_SIZE( wxCollapsiblePane::OnSize )
END_EVENT_TABLE()

bool wxCollapsiblePane::Create( wxWindow *parent, wxWindowID id, const wxString& label, const wxPoint& pos,
                                const wxSize& size, long style, const wxValidator& val, const wxString& name ) {
  if( gtk_check_version( 2, 4, 0 ) )
    return wxGenericCollapsiblePane::Create( parent, id, label,
           pos, size, style, val, name );
  m_needParent = true;
  m_acceptsFocus = true;
  m_bIgnoreNextChange = false;
  if( !PreCreation( parent, pos, size ) ||
      !wxControl::CreateBase( parent, id, pos, size, style, val, name ) ) {
    wxFAIL_MSG( wxT( "wxCollapsiblePane creation failed" ) );
    return false;
  }
  m_widget =
    gtk_expander_new_with_mnemonic( wxGTK_CONV( GTKConvertMnemonics( label ) ) );
  g_signal_connect( m_widget, "notify::expanded",
                    G_CALLBACK( gtk_collapsiblepane_expanded_callback ), this );
  m_insertCallback = gtk_collapsiblepane_insert_callback;
  m_pPane = new wxPanel( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
                         wxTAB_TRAVERSAL | wxNO_BORDER );
  gtk_widget_show( GTK_WIDGET( m_widget ) );
  m_parent->DoAddChild( this );
  PostCreation( size );
  m_szCollapsed = GetBestSize();
  return true;
}

wxSize wxCollapsiblePane::DoGetBestSize() const {
  if( !gtk_check_version( 2, 4, 0 ) ) {
    wxASSERT_MSG( m_widget, wxT( "DoGetBestSize called before creation" ) );
    GtkRequisition req;
    req.width = 2;
    req.height = 2;
    ( * GTK_WIDGET_CLASS( GTK_OBJECT_GET_CLASS( m_widget ) )->size_request )
    ( m_widget, &req );
    return wxSize( req.width, req.height );
  }
  return wxGenericCollapsiblePane::DoGetBestSize();
}

void wxCollapsiblePane::Collapse( bool collapse ) {
  if( !gtk_check_version( 2, 4, 0 ) ) {
    if( IsCollapsed() == collapse ) {
      return;
    }
    m_bIgnoreNextChange = true;
    gtk_expander_set_expanded( GTK_EXPANDER( m_widget ), !collapse );
  } else {
    wxGenericCollapsiblePane::Collapse( collapse );
  }
}

bool wxCollapsiblePane::IsCollapsed() const {
  if( !gtk_check_version( 2, 4, 0 ) ) {
    return !gtk_expander_get_expanded( GTK_EXPANDER( m_widget ) );
  }
  return wxGenericCollapsiblePane::IsCollapsed();
}

void wxCollapsiblePane::SetLabel( const wxString &str ) {
  if( !gtk_check_version( 2, 4, 0 ) ) {
    gtk_expander_set_label( GTK_EXPANDER( m_widget ), wxGTK_CONV( str ) );
  } else {
    wxGenericCollapsiblePane::SetLabel( str );
  }
}

void wxCollapsiblePane::OnSize( wxSizeEvent &ev ) {
  m_pPane->SetSize( ev.GetSize().x, ev.GetSize().y - m_szCollapsed.y );
  m_pPane->Layout();
}
